﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Collections;

namespace FrameworkLib.Security
{
    public class SecurityHelper
    {
        private void CheckSecurity(object o, List<int> processedControls)
        {
            // Avoid stack overflow due to properties like Parent 
            // or TopLevelControl         
            if (o == null)
                return;

            int hash = o.GetHashCode();
            bool processed = false;
            foreach (int ctrlHash in processedControls)
            {
                if (ctrlHash == hash)
                {
                    processed = true;
                    break;
                }
            }

            if (processed == true)
                return;

            processedControls.Add(hash);

            System.Reflection.FieldInfo[] fields = o.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic);

            foreach (System.Reflection.FieldInfo field in fields)
            {
                object[] attrs =
                    field.GetCustomAttributes(
                    typeof(AuthorizationAttribute), false);
                if (attrs.Length > 0)
                {
                    // We only allow one attribute (AllowMultiple = false)
                    AuthorizationAttribute attr = (AuthorizationAttribute)attrs[0];

                    try
                    {
                        if (HasAccess(field.Name, attr.OperationName) == false)
                        {
                            object ctrl = field.GetValue(o);
                            PropertyInfo propInfo = ctrl.GetType().GetProperty(attr.PropertyName);
                            if (propInfo != null)
                            {
                                propInfo.SetValue(ctrl, attr.PropertyValue, null);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        // not fatal
                        // TODO: log the error 
                    }
                }

                if (field.GetType().IsClass)
                {
                    object childO = field.GetValue(o);

                    if (childO is System.ComponentModel.Component)
                    {
                        CheckSecurity(childO, processedControls);
                    }
                    else if (childO is IEnumerable)
                    {
                        foreach (object item in (IEnumerable)childO)
                        {
                            if (item is System.ComponentModel.Component)
                            {
                                CheckSecurity(item, processedControls);
                            }
                        }
                    }
                }
            }
        }

        private bool HasAccess(string controlName, string operationName)
        {
            bool result = false;

            System.Security.Principal.IPrincipal m_OperatorePrincipale = System.Threading.Thread.CurrentPrincipal;
            if (m_OperatorePrincipale.IsInRole(operationName))
            {
                result = true;
            }

            return result;
        }
    }
}
